package com.taotao.config;

import com.google.common.util.concurrent.RateLimiter;
import com.taotao.service.SWRateLimiter;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author wangjin
 * @title: AopRateLimiter
 * @projectName sw-gateway
 * @description:
 * @date 2021/12/9 16:08
 */
@Aspect
@Component
@Slf4j
public class AopRateLimiter {
    /**
     * 定义RateLimiter 限流集合容器
     */
    private static ConcurrentHashMap<String, RateLimiter> rateLimiters = new ConcurrentHashMap<>();

    /**
     * 环绕通知
     *
     * @param pjp
     * @return
     */
    @Around(value = "@annotation(com.taotao.service.SWRateLimiter)")
    public Object currentLimit(ProceedingJoinPoint pjp) throws Throwable {
        // 1.获取拦截到目标方法
        MethodSignature methodSignature = (MethodSignature) pjp.getSignature();
        // 2.获取目标方法
        Method method = methodSignature.getMethod();
        // 3.获取目标方法上的注解
        SWRateLimiter mayiktRateLimiter = method.getDeclaredAnnotation(SWRateLimiter.class);
        // 4.获取到请求方法名称
        String requestMethodName = method.getName();
        // 5.从容器查找该 请求方法 对应的 rateLimiter 是否有创建 如果没有创建 就创建
        RateLimiter rateLimiter = rateLimiters.get(requestMethodName);
        if (rateLimiter == null) {
            // 防止多个线程同时创建RateLimiter 使用双重检验锁 判断
            synchronized (this) {
                if (rateLimiter == null) {
                    // 获取注解上mayiktRateLimiter.aqs参数值
                    rateLimiter = RateLimiter.create(mayiktRateLimiter.aqs());
                    rateLimiters.put(requestMethodName, rateLimiter);
                }
            }
        }
        try {
            // 6.判断是否被限流 如果是被限流 则 获取mayiktRateLimiter注解中的 msg 返回
            if (!rateLimiter.tryAcquire()) {
                return mayiktRateLimiter.msg();
            }
        } catch (Exception e) {
            log.error("<e:{}>", e);
        }
        // 没有被限流 则直接放行
        return pjp.proceed();
    }
}












